package dymnd;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Container;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InvalidClassException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintStream;
import java.util.ArrayList;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.SpinnerModel;
import javax.swing.SpinnerNumberModel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

import dymnd.image.Layer;
import dymnd.io.ServerConfig;
import dymnd.net.NetworkManager;
import dymnd.net.Packet;
import dymnd.net.PaintPacket;
import dymnd.net.QueryPacket;
import dymnd.plugin.PaintPlugin;
import dymnd.plugin.Plugin;
import dymnd.plugin.PluginLoader;
import dymnd.ui.Canvas;
import dymnd.ui.DragViewport;
import dymnd.ui.DymndConstants;
import dymnd.ui.DymndFileFilter;
import dymnd.ui.JpegFileFilter;
import dymnd.ui.MessagePane;
import dymnd.ui.PDialog;
import dymnd.ui.PNGFileFilter;
import dymnd.ui.PluginOptionPanel;
import dymnd.ui.WorkspaceLayoutManager;
import dymnd.ui.color.SwatchPanel;
 

/*
 * CREDITS
 * 
 * Program written and developed by Grant Pearson, and is (C) Grant Pearson 2008-2009 (grant.m.pearson@gmail.com)
 * 
 *                                  

 * 
 * Icon-set for this program is under a Creative Commons Attribution 3.0 license (http://creativecommons.org/licenses/by/3.0/)
 * Icons created by: http://www.pinvoke.com/
 */



//Future Applications:
/*
 * Write a dymnd image 'compiler' - including a scripting language or API for images and tutorials
 * 
 * compiler allows for the editing of WIP files and UDI files, from individual packet removal/addition to the addition or removal of entire branches of packets
 * Display packets as branches. each layer and user is a tree. 
 */



/*-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/
 * Features to implement:
 *  Magnification window; zooms in on a specified region in a window only, keeping the main
 *  perspective at the normal/previous zoom level, allowing the user to preview their work.
 *  
 *  **High Priority** rewrite main window layout manager
 *  
 *  **High Priority** build new panel components (panel in-window, JPopupDialog panels) 
 *  
 *  Finished!!**High Priority** Rewrite plugins to implement new bounding rectangle code, as well as to use AlphaComposite code 
 *  
 *  
 *  Polish all dialogs and write an automated dialog adding method
 *  
 * Write a server list; some way to list known dymnd servers, as well as a history of favorites 
 *
 * Make chat dialog scrollable
 * 
 * *done* Fix "New Image" menu item
 * 
 * Add the ability to OPEN files
 * 
 * Add a Text plugin, for inserting text
 * 
 * Add a line tool
 * 
 * Add a shape drawing tool
 * 
 * Add a fill tool
 * 
 * Tweak tablet pressure sensetivity
 * 
 * Smooth the brush tool's size, make re-sizing the brush seamless
 * 
 * Finish implementing Network Options dialog
 * 
 * Add the ability to save these formats:
 * 			PNG
 * 			JPEG
 * 			TIFF
 * 			BMP
 * 			GIF
 * 			WIP - Work In Progress (Custom dymnd format)
 * 			**If possible, add PSD compatability
 * 
 * Add a record-feature to save a drawing as it's created for later playback
 * 
 * Add support for Python-based plugins
 * 
 * 
 * *done* For the server, add a routine for removing dead sockets and reporting to clients that the socket has been dropped
 * 
 * Add a way for users to disconnect from the server
 * 
 * Set something up to notify users when they lose connection to the server
 * 
 * 
 * Add recently opened menu
 * ****VERY IMPORTANT - Add support for transparent line drawing
 * 
 * 
 * **IMPORTANT! Add support for a layer dialog and the adding and deletion of layers
 * 
 * 
 * Consider adding accelerated CUDA code to make rendering faster - CUDA /must/ be optional, and is a /low priority/ goal.
 * 
 * 
 * 
 * *done* Fix save menu item - throws exception if no image is created first
 *-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/*/


//All methods that show a dialog shall be called dialog<Function>()


//make Client serializeable, allowing the program to be stopped and the current session to be saved to a file, even sent to another computer




public class Client extends JFrame implements ActionListener, WindowListener	{
	
	//Static methods, called while loading
	
	static{
		load();
	}
	
	static Plugin[] pluginList;
	private static void load()	{
		loadPluginList();
		
	}
	
	private static void loadPluginList()	{
		pluginList = PluginLoader.loadPlugins(PLUGIN_DIRECTORY);
	
	}
	
	
	BufferedImage cursorImage;
	Canvas canvas;
	ArrayList<Layer> layers = new ArrayList<Layer>(); // an array of local layers
	boolean hosting = false;	
	Settings settings; // Settings contains all of the settings for the program
	boolean hasSaved = true; // set this to true if the user has saved and not modified the document
	
	boolean mouseReleased = false;
	
	JDialog toolDialog = null;
	//a stack of all incoming packets
	////// May no longer be needed, consider removal ///////
	//ArrayList<PaintPacket> packetStack = new ArrayList<PaintPacket>();	
	
	
	int selectedLayer = 0; //The currently selected layer
	Color selectedColor = Color.black; //The currently selected color
	Color secondaryColor = Color.white; // The secondary color	
	
	int lastX = -1; // x coordinate from the last paint cycle
	int lastY = -1; // y coordinate from the last paint cycle
	double pressure = 1;
	
	//ArrayList<PacketSet[]> undoStack = new ArrayList<PacketSet[]>();
	//ArrayList<Layer[]> undoStack = new ArrayList<Layer[]>();
	
	//network related variables
	//boolean networkModeOn = false;
	
	boolean eraseSettings = false;
	//UI related variables
	JDialog swatchesDialog; // toggleable window for displaying swatches
	JDialog layersDialog;  // toggleable window for displaying layers
	
	JTextField brushSizeField; // A field where the user can specify the size of the brush
	int undoCount = 10;
	
	JDialog layerDialog;
	JList layerJList; // A JList to display active layers
	
	
	
	public static final int TOOL_SELECT = 1;
	public static final int TOOL_COPY = 2;
	public static final int TOOL_PASTE = 3;
	public static final int TOOL_CUT = 4;
	public static final int TOOL_PLUGIN = 15;
	public static final int TOOL_CHAT = 16;		
	public static final int TOOL_PING = 17;
	public static final int TOOL_PONG = 18;
	public static final int TOOL_INIT_PACKET = 19;
	public static final int TOOL_PEER_DISCONNECTED = 20;
	public static final int TOOL_PEER_CONNECTED = 21;
	
	private int tool = TOOL_PLUGIN;
	
	boolean debugMode = false;
	
	JList layerList;
	private final static String PLUGIN_DIRECTORY = "plugins/";
	
	ArrayList<PaintPlugin> paintPlugins = new ArrayList<PaintPlugin>();
	ArrayList<JButton>	toolButtons = new ArrayList<JButton>();
	
	//ArrayList<JDialog>	dialogs = new ArrayList<JDialog>();
	private int selectedPlugin = 0;
	
	PluginOptionPanel topToolbar;
	
	JDialog chatDialog;
	JTextArea chatTextArea = new JTextArea();
	Layer scratchLayer;
	
	
	Variables variables = new Variables();
	
	NetworkManager networkManager;
	boolean networkConnected = false;
	
	public Client(String[] args)	{
	
		
		//Parse command line arguments
		for(int i = 0; i < args.length; i++)	{
			if(args[i].startsWith("--debug"))
				debugMode = true;
			
		} //Command line arguments END
		
		networkManager = new NetworkManager(this);
		
		try {
			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
		} catch (ClassNotFoundException e1) {
			e1.printStackTrace();
		} catch (InstantiationException e1) {
			e1.printStackTrace();
		} catch (IllegalAccessException e1) {
			e1.printStackTrace();
		} catch (UnsupportedLookAndFeelException e1) {
			e1.printStackTrace();
		}
		
		setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
		addWindowListener(this);
		
		settings = loadSettings(); // Load configuration
		setSize((Integer)settings.get("mainWindowWidth"), (Integer)settings.get("mainWindowHeight")); //set the default size of the window
		getContentPane().setLayout(new WorkspaceLayoutManager(this));
		
		
				
		try {
			initMenuBar();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} //initialize the menu bar
		getContentPane().setBackground(new Color(230, 230, 230));
		
		topToolbar = createTopMenuPane();
		getContentPane().add(topToolbar, WorkspaceLayoutManager.COMPONENT_UTILITY_MENU);
		
		setVisible(true); // set the frame to visible
		setIconImage(loadImage("resources/dymnd_icon.png"));
		//scratchLayer = createLayer(getWidth(), getHeight());
		loadPlugins(); // Load all plugins
		processSettings();
		
		setTitle("Dymnd - Collaborative Network Painting Utility");		    
		
		validate(); // make sure everything is placed correctly, and that the layout manager runs
		
		topToolbar.onPluginSelected(paintPlugins.get((Integer)settings.get("selectedPlugin")));
		topToolbar.getComponent(0).repaint();
		
	    requestFocus();
	    System.gc(); 
	    
	}
	
	
	
	//dialog for holding a SwatchPanel
	JDialog swatchDialog;
	/**
	 * Create and show or hide a dialog for selecting swatches.
	 */
	private void toggleSwatchChooserDialog()	{
		if(swatchDialog == null)	{
			SwatchPanel panel = new SwatchPanel();
			panel.setActionListener(this);
			
			if(settings.containsKey("swatchDialogWidth") && settings.containsKey("swatchDialogHeight"))
				panel.setSize((Integer)settings.get("swatchDialogWidth"), (Integer)settings.get("swatchDialogHeight"));
			else
				panel.setSize(200, 200);
			
			swatchDialog = createDialog(panel);
			if(settings.containsKey("swatchDialogX") && settings.containsKey("swatchDialogY"))
				swatchDialog.setLocation((Integer)settings.get("swatchDialogX"), (Integer)settings.get("swatchDialogY"));
			else
				swatchDialog.setLocation(650, 150);
			
			swatchDialog.setVisible(true);
			
			
			
		}	else {
			swatchDialog.setVisible(!swatchDialog.isVisible());
		}
		
		
	}
	
	/**
	 * Creates a JDialog with the specified container
	 * @param c - the container to add
	 * @return - returns a JDialog with it's only children being the specified Container and it's children
	 */
	private JDialog createDialog(Container c)	{
		JDialog d = new JDialog(this);
		d.setSize(c.getSize());
		d.add(c);
		return d;
	}
	
	
	private Cursor createCursor(int rad)	{
		cursorImage = new BufferedImage(32, 32, BufferedImage.TYPE_4BYTE_ABGR);
		Graphics2D g = cursorImage.createGraphics();
		g.setColor(DymndConstants.COLOR_SCRATCH_GRAPHICS);
		//g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		//g.setStroke(new BasicStroke(0.1f));
		if(rad*2 < 32)	{
			g.fill(new java.awt.geom.Ellipse2D.Double(0, 0, rad*2, rad*2));
			//g.setColor(new Color(100, 100, 120));
			//g.fill(new java.awt.geom.Ellipse2D.Double(0, 0, rad*1.5, rad*1.5));
			return Toolkit.getDefaultToolkit().createCustomCursor(cursorImage, new Point(rad, rad), "brushCursor");
		}
		else	{
			g.fill(new java.awt.geom.Ellipse2D.Double(0, 0, 32, 32));
			return Toolkit.getDefaultToolkit().createCustomCursor(cursorImage, new Point(32/2, 32/2), "brushCursor");
		
		}
		
	}
	
	
	
	
	private void loadPlugins()	{
		Plugin[] p = pluginList;
		for(int i = 0; i < p.length; i++)	{
			
			if(p[i] != null && p[i] instanceof PaintPlugin){
				//p[i].setBus(this); //***Make sure to move me to the general Plugins area...
				//JLabel l = new JLabel("Select a tool...");
				//l.setLocation(20, 10);
				//l.setSize(300, 20);
				//setToolbar(((PaintPlugin)p[settings.selectedPlugin]).getToolbar(new Dimension(getWidth(), 50)));
				//canvas.setCursor(createCursor(toolPlugins.get(selectedPlugin).getRadius()));
				paintPlugins.add((PaintPlugin)p[i]);
				addToolPlugin(paintPlugins.get(i));
			}
			
		}
		
	}
	
	
	
	private void unloadPlugins()	{
		for(int i = 0; i < paintPlugins.size(); i++)	{
			paintPlugins.get(i).onUnload();
		}
	}
	//Call t.interupt() to stop the pane.
	private Thread showWorkPane(String message)	{
		MessagePane glassPane = new MessagePane(message);
		glassPane.setSize(getWidth(), getHeight());
		Thread t = new Thread(glassPane);
		t.start();
		setGlassPane(glassPane);
		glassPane.setVisible(true);
		return t;
	}
	
	JPanel toastPanel = new JPanel();
	
	/*private void toastMessage(String t)	{
		ToastPanel toast = new ToastPanel(t, Color.black, 5000);
		setGlassPane(toast);
		
		toast.setVisible(true);
		new Thread(toast).start();
		
		
		
	}*/
	
	private void addToolPlugin(PaintPlugin t)	{
		//toolPlugins.add(t);
		
		JButton b = new JButton(t.getIcon());
		b.setActionCommand("TOOL_PLUGIN " + (paintPlugins.size() - 1));
		b.addActionListener(this);
		b.setIcon(t.getIcon());
		b.setToolTipText(t.getTooltip());
		
		toolButtons.add(b);
	}
	
	private void processSettings()	{
		if(settings.containsKey("showToolDialog"))
			if((Boolean)settings.get("showToolDialog"))
				showToolDialog();
		
		if(settings.containsKey("showSwatchesDialog"))
			if((Boolean)settings.get("showSwatchesDialog"))
				toggleSwatchChooserDialog();
	}
	
	private void saveImage(BufferedImage buffer)	{
		
		
		JFileChooser chooser = new JFileChooser();
		chooser.setCurrentDirectory(new File((String)settings.get("lastDirectory")));
		//chooser.setFileFilter(new ImageFileFilter());
		chooser.setFileFilter(new JpegFileFilter());
		chooser.setFileFilter(new PNGFileFilter());
		chooser.setAcceptAllFileFilterUsed(false);
		chooser.showSaveDialog(this);
		
		File f = chooser.getSelectedFile();
		
		//System.out.println("Selected file: " + f.getPath().toString());
		
		try	{
			if(f != null)	{
				if(f.isDirectory())	{
					settings.put("lastDirectory", f.getPath().toString());
				}	else	{
					settings.put("lastDirectory", f.getParent());
				}
				
				if(chooser.getFileFilter() instanceof DymndFileFilter)	{
					DymndFileFilter filter = (DymndFileFilter) chooser.getFileFilter();
					//Filter for PNG images
					if(!f.toString().endsWith(filter.getExtension()))	{
						f = new File(f.getPath() + filter.getExtension());
					}
					//filter for JPEG images
					if(filter.getExtension() == new PNGFileFilter().getExtension())
						javax.imageio.ImageIO.write(buffer, "png", f);
					else if(filter.getExtension() == new JpegFileFilter().getExtension())	{
						BufferedImage bi = new BufferedImage(buffer.getWidth(), buffer.getHeight(), BufferedImage.TYPE_INT_RGB);
						Graphics2D g = bi.createGraphics();
						g.setColor(Color.white);
						g.fillRect(0, 0, bi.getWidth(), bi.getHeight());
						g.drawImage(buffer, 0, 0, null);
						
						javax.imageio.ImageIO.write(bi, "jpg", f);
					}
				}
				hasSaved = true;
			}
					
		}	catch(Exception x)	{
			x.printStackTrace();
		}
	}
	
	private void dialogNetworkOptions()	{
		final JDialog jd = new JDialog(this);
		jd.setSize(200, 200);
		jd.setLocation(((Dimension)settings.get("screenSize")).width / 2 - jd.getWidth()/2, ((Dimension)settings.get("screenSize")).height /2 - jd.getHeight()/2);
		jd.setVisible(true);
		jd.setLayout(null);
		jd.setTitle("Network Options");
		//Layout looks like this
		//Label:Field
		//   [ok]
		
		//Fields: nick, default host, default port, default canvas size
		ActionListener al;
		int labelWidth = 100;
		int fieldWidth = 100;
		int height = 20;
		
		int labelX = 10;
		int y = 10;
		int fieldX = labelX+labelWidth;
		
		JLabel nickLabel = new JLabel("Nick: ");
		nickLabel.setSize(labelWidth, height);
		nickLabel.setLocation(labelX, y);
		jd.add(nickLabel);
		
		final JTextField nickField = new JTextField((String)settings.get("username"));
		nickField.setSize(fieldWidth, height);
		nickField.setLocation(fieldX, y);
		jd.add(nickField);
		
		JLabel hostLabel = new JLabel("Default Host: ");
		hostLabel.setSize(labelWidth, height);
		hostLabel.setLocation(labelX, y+=height + 10);
		jd.add(hostLabel);
		
		final JTextField hostField = new JTextField((String)settings.get("networkHost"));
		hostField.setSize(fieldWidth, height);
		hostField.setLocation(fieldX, y);
		
		jd.add(hostField);
		
		JLabel portLabel = new JLabel("Default Port: ");
		portLabel.setSize(labelWidth, height);
		portLabel.setLocation(labelX, y+=height + 10);
		jd.add(portLabel);
		
		final JTextField portField = new JTextField(((Integer)settings.get("networkPort")).toString());
		portField.setSize(fieldWidth, height);
		portField.setLocation(fieldX, y);
		jd.add(portField);
		
		JButton okButton = new JButton("Ok");
		okButton.setSize(50, 20);
		okButton.setLocation((labelWidth+fieldWidth)/2 -okButton.getWidth() /2, y += height +10);
		jd.add(okButton);
		
		al = new ActionListener()	{
			public void actionPerformed(ActionEvent e)	{
				settings.put("networkPort", Integer.parseInt(portField.getText()));
				settings.put("networkHost", hostField.getText());
				settings.put("username", nickField.getText());
				jd.dispose();
			}
		};
		
		portField.addActionListener(al);
		hostField.addActionListener(al);
		nickField.addActionListener(al);
		okButton.addActionListener(al);
	}

	//network method, new.
	public synchronized void onPacket(Packet p)	{
		switch(p.packetType)	{
		case Packet.PACKET_TYPE_PLUGIN:
			doPaint(p, false);
		}
	}
	
	
	public void onConnectionLost()	{
		networkConnected = false;
	}
	
	//OLD METHOD - remove
	public void onPaintPacketRecieved(PaintPacket p)	{
		Client.debugMsg("Recieved packet.");
	}
	
	
	//Write settings to a file
	private Settings loadSettings()	{
		Settings s = Settings.defaultSettings();
		try {
			File f = new File("settings.obj");
			if(f.exists())	{
				if(!eraseSettings)	{
					FileInputStream fis = new FileInputStream(f);
					ObjectInputStream in = new ObjectInputStream(fis);
					s = (Settings) in.readObject();
					in.close();
				}
				else	{
					f.delete();
				}
			}
			
			
		}	catch(InvalidClassException	x)	{
			eraseSettings = true;
			loadSettings();
			
		}	catch(IOException x)	{
			x.printStackTrace();
		}	catch(ClassNotFoundException x)	{
			x.printStackTrace();
		}
		
		return s;
	}
	
	//Write out settings
	private void saveSettings()	{
		try {
			settings.put("mainWindowWidth", new Integer(getWidth()));
			settings.put("mainWindowHeight", new Integer(getHeight()));
			//settings.width = getWidth();
			//settings.height = getHeight();
			
			if(swatchesDialog != null)	{
				settings.put("swatchesDialogX", new Integer(swatchesDialog.getX()));
				settings.put("swatchesDialogY", new Integer(swatchesDialog.getY()));
				//settings.swatchesDialogX = swatchDialog.getX();
				//settings.swatchesDialogY = swatchDialog.getY();
				settings.put("swatchesDialogWidth", new Integer(swatchesDialog.getWidth()));
				settings.put("swatchesDialogHeight", new Integer(swatchesDialog.getHeight()));
				//settings.swatchDialogWidth = swatchDialog.getWidth();
				//settings.swatchDialogHeight = swatchDialog.getHeight();
				
				settings.put("showSwatchesDialog", ((Boolean)swatchesDialog.isVisible()));
			}
			//settings.showSwatches = swatchDialog.isVisible();
			
			//settings.canvasWidth = canvas.getWidth();
			//settings.canvasHeight = canvas.getHeight();
			
			File f = new File("settings.obj");
			FileOutputStream fis = new FileOutputStream(f);
			ObjectOutputStream out = new ObjectOutputStream(fis);
			out.writeObject(settings);
			out.close();
			
		}	catch(Exception x)	{
			x.printStackTrace();
		}
		
		
	}
	
	
	
	private void undo()	{
		
	}
	
	private void redo()	{
		
	}
	
	
	/*
	 * Initialize the menu bar
	 */
	private void initMenuBar() throws IOException	{
		final JLabel DIVIDER_LABEL = new JLabel("        -------------------");
		DIVIDER_LABEL.setEnabled(false);
		final JLabel DIVIDER_LABEL1 = new JLabel("        -------------------");
		DIVIDER_LABEL1.setEnabled(false);
		
		JMenuBar menuBar = new JMenuBar();
		//File menu
		JMenu fileMenu = new JMenu("File");
			//New Image menu item
			JMenuItem newImageMenu = new JMenuItem("New");
			newImageMenu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, InputEvent.CTRL_MASK));
			newImageMenu.addActionListener(this);
			newImageMenu.setIcon(new ImageIcon(loadImage("resources/ui/document__plus.png")));
			fileMenu.add(newImageMenu);
			
			//save menu item
			JMenuItem saveMenuItem = new JMenuItem("Save");
			saveMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_MASK));
			saveMenuItem.addActionListener(this);
			saveMenuItem.setIcon(new ImageIcon(loadImage("resources/ui/disk__pencil.png")));
			fileMenu.add(saveMenuItem);
			
			//close menu item
			JMenuItem closeMenuItem = new JMenuItem("Close");
			//saveMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_MASK));
			closeMenuItem.addActionListener(this);
			closeMenuItem.setIcon(new ImageIcon(loadImage("resources/ui/cross.png")));
			fileMenu.add(closeMenuItem);
			
			//DIVIDER
			fileMenu.add(DIVIDER_LABEL1);
			
			
			//exit menu item
			JMenuItem exitMenu = new JMenuItem("Exit");
			exitMenu.addActionListener(this);
			fileMenu.add(exitMenu);
			
		menuBar.add(fileMenu);
		
		//Edit menu		
		JMenu editMenu = new JMenu("Edit");
			
			//Undo menu item
			JMenuItem undoMenuItem = new JMenuItem("Undo");
			undoMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Z, InputEvent.CTRL_MASK));
			undoMenuItem.addActionListener(this);
			editMenu.add(undoMenuItem);
		menuBar.add(editMenu);
		
		//View menu
		JMenu viewMenu = new JMenu("View");
		
			JMenuItem lostCanvasItem = new JMenuItem("I've lost my canvas!");
			lostCanvasItem.addActionListener(this);
			viewMenu.add(lostCanvasItem);
			
		menuBar.add(viewMenu);
		
		
		//Layer Menu
		JMenu layerMenu = new JMenu("Layer");
			
			//Add New Layer MenuItem
			JMenuItem addNewLayerMenuItem = new JMenuItem("New Layer");
			addNewLayerMenuItem.addActionListener(this);
			addNewLayerMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, InputEvent.ALT_MASK));
			addNewLayerMenuItem.setIcon(new ImageIcon(loadImage("resources/ui/layer__plus.png")));
			layerMenu.add(addNewLayerMenuItem);
				
				
		
		menuBar.add(layerMenu);
		
		//Networking menu
		JMenu networkMenu = new JMenu("Networking");
			
			//Host menu
			JMenuItem hostMenuItem = new JMenuItem("Host");
			//hostMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_H, InputEvent.CTRL_MASK));
			hostMenuItem.addActionListener(this);
			hostMenuItem.setIcon(new ImageIcon(loadImage("resources/ui/socket.png")));
			networkMenu.add(hostMenuItem);
		
			//Connect menu 
			JMenuItem connectMenuItem = new JMenuItem("Connect to...");
			connectMenuItem.addActionListener(this);
			connectMenuItem.setIcon(new ImageIcon(loadImage("resources/ui/plug.png")));
			networkMenu.add(connectMenuItem);
			
			//Disconnect menu
			JMenuItem disconnectMenuItem = new JMenuItem("Disconnect");
			disconnectMenuItem.addActionListener(this);
			disconnectMenuItem.setIcon(new ImageIcon(loadImage("resources/ui/plug_minus.png")));
			//if(!networkModeOn)
				//disconnectMenuItem.setEnabled(false);
			networkMenu.add(disconnectMenuItem);
			
			
			networkMenu.add(DIVIDER_LABEL);
			
			//Networking options menu
			JMenuItem networkOptionsMenu = new JMenuItem("Options");
			networkOptionsMenu.setActionCommand("Network Options");
			networkOptionsMenu.addActionListener(this);
			networkOptionsMenu.setIcon(new ImageIcon(loadImage("resources/ui/gear__pencil.png")));
			networkMenu.add(networkOptionsMenu);
			
		menuBar.add(networkMenu);
		
		//Window menu
		JMenu windowMenu = new JMenu("Window");
			
			//Color swatches menu item
			JMenuItem colorSwatchMenuItem = new JMenuItem("Swatches");
			colorSwatchMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_1, InputEvent.CTRL_MASK));
			colorSwatchMenuItem.addActionListener(this);
			colorSwatchMenuItem.setIcon(new ImageIcon(ImageIO.read(new File("resources/ui/palette.png"))));
			windowMenu.add(colorSwatchMenuItem);

			//Layers menu item
			JMenuItem layerMenuItem = new JMenuItem("Layers");
			layerMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_2, InputEvent.CTRL_MASK));
			layerMenuItem.addActionListener(this);
			layerMenuItem.setIcon(new ImageIcon(loadImage("resources/ui/layers.png")));
			windowMenu.add(layerMenuItem);
			
			//Tools menu item
			JMenuItem toolsMenuItem = new JMenuItem("Tools");
			toolsMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_3, InputEvent.CTRL_MASK));
			toolsMenuItem.addActionListener(this);
			toolsMenuItem.setIcon(new ImageIcon(loadImage("resources/ui/wrench_screwdriver.png")));
			windowMenu.add(toolsMenuItem);
			
			//Chat Menu Item
			JMenuItem chatMenuItem = new JMenuItem("Chat");
			chatMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_4, InputEvent.CTRL_MASK));
			chatMenuItem.addActionListener(this);
			chatMenuItem.setIcon(new ImageIcon(loadImage("resources/ui/balloon.png")));
			windowMenu.add(chatMenuItem);
		menuBar.add(windowMenu);
	
		//add the menu to the frame
		setJMenuBar(menuBar);
		

		
	}
	
	
	/*
	 * Initialize layers
	 */
	private void initLayers(int count)	{
		layers.ensureCapacity(count);
		
		for(int i = 0; i < count; i++)	
			layers.add(createLayer((Integer)settings.get("canvasWidth"), (Integer)settings.get("canvasHeight"), (String)settings.get("username")));
		
		scratchLayer = createLayer((Integer)settings.get("canvasWidth"), (Integer)settings.get("canvasHeight"), null);
		
	}
	
	//creates a new transparent layer - Should be graphics accelerated
	
	private Layer createLayer(int width, int height, String owner)	{
		Layer l;
		l = new Layer(width, height, owner);
		l.setName("New Layer " + layers.size());
		
		
		return l;
	}
	
	private Layer createLayer(int width, int height, String owner, String layerName)	{
		Layer l;
		l = new Layer(width, height, owner);
		l.setName(layerName);
		
		
		return l;
	}
	
	private Image loadImage(String file)	{
		return Toolkit.getDefaultToolkit().getImage(file);
	}
	
	/**
	 * Initialize the Canvas that the user draws on
	 * @return
	 */
	private Canvas initCanvas()	{
		
		
		
		
		Canvas pc = new Canvas((Integer)settings.get("canvasWidth"), (Integer)settings.get("canvasHeight"));
		pc.setPreferredSize(new Dimension((Integer)settings.get("canvasWidth"), (Integer)settings.get("canvasHeight")));
		
		
		
		
		final DragViewport viewport = new DragViewport();
		viewport.setSize(getWidth(), getHeight());
		//canvas = 
		pc.setLocation(0, 0);
		
		viewport.setView(pc);
		
		//pane.setBackground(getBackground());
		//pc.setBorder(BorderFactory.createEtchedBorder(Color.white, Color.gray));
		
		
		
		getContentPane().add(viewport, WorkspaceLayoutManager.COMPONENT_CANVAS);
		//getContentPane().add(pc, WorkspaceLayoutManager.COMPONENT_CANVAS);
		//pc.add(pane);
		
		//setLayer(0); // set the currently selected layer 
		
		//init a mouse listener - replace this later with an 
		//input module
		addMouseListener(new MouseAdapter()	{
			
			public void mouseReleased(MouseEvent e)	{
				viewport.mouseReleased(e);
				
				int x = e.getX() - viewport.getX() +viewport.getViewPosition().x;
				int y = e.getY() - (viewport.getY() + 50) + viewport.getViewPosition().y ;
				//mouseReleased = true;
				Packet pack = new Packet();
				pack.packetType = Packet.PACKET_TYPE_PLUGIN;
				pack.mouseAction = Packet.MOUSE_ACTION_RELEASED;
				pack.x = x;
				pack.y = y;
				
				pack.lastX = lastX;
				pack.lastY = lastY;
				pack.pressure = 0;;
				//pack.inputReleased = true;
				//pack.rad = 5;
				//pack.tool = tool;
				pack.radius = 5;
				if(tool == TOOL_PLUGIN)
					pack.pluginHash = paintPlugins.get(selectedPlugin).getHashValue();
				if(layerList != null)
					selectedLayer = layerList.getSelectedIndex();
				pack.layerIndex = selectedLayer;
				
				//pack.primaryColor = new Color(settings.primaryColor.getRed(), settings.primaryColor.getGreen(), settings.primaryColor.getBlue(), 0);
				
				
				
				//System.out.println("" + pack.pressure);
				doPaint(pack, true);
				lastX = x;
				lastY = y;
				
				
			}
			
			
			
			public void mouseEntered(MouseEvent e)	{
				if(canvas != null)
					canvas.setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR));
			}
		});
		
		addMouseMotionListener(new TabletAdapter(this)	{
			
			public void pressureEvent(double pres)	{
				pressure = pres;
			}
			
			public void mouseDragged(MouseEvent e)	{
				if(e.isControlDown() && !e.isAltDown() && !e.isShiftDown())	{
					viewport.mouseDragged(e);
				}	else	{
				
				int x = e.getX() - viewport.getX() +viewport.getViewPosition().x;
				int y = e.getY() - (viewport.getY() + 50) + viewport.getViewPosition().y ;
				
				  
				Packet pack = new Packet();
				pack.packetType = Packet.PACKET_TYPE_PLUGIN;
				pack.x = x;
				pack.y = y;
				
				pack.lastX = lastX;
				pack.lastY = lastY;
				pack.pressure = pressure;
				pack.mouseAction = Packet.MOUSE_ACTION_PRESSED;
				//pack.pluginDefined.put("brushRadius", new Integer(-1)); //settings.brushDiameter /2;
				pack.radius = -1;
				//pack.tool = tool;
				if(tool == TOOL_PLUGIN)
					pack.pluginHash = paintPlugins.get(selectedPlugin).getHashValue();
				if(layerList != null)
					selectedLayer = layerList.getSelectedIndex();
				pack.layerIndex = selectedLayer;
				//selectedColor = new Color(0, 0, 0, 50);
				
				pack.primaryColor = (Color)settings.get("primaryColor");
				pack.secondaryColor = (Color)settings.get("secondaryColor");
				
				
				
				//System.out.println("" + pack.pressure);
				doPaint(pack, true);
				mouseReleased = false;
				lastX = x;
				lastY = y;
				
				
				
				//System.out.print("Packet:<");
				/*if(networkConnected)
					networkManager.writePacket(pack);*/
					//System.out.println("Sending packet from listener");
				
				
				}
			}
			  
			
			
			
			
		});
		System.gc();
		return pc;
	}
	
	/**
	 * Create the menu pane that goes on the top of the main window
	 * @return
	 */
	private PluginOptionPanel createTopMenuPane()	{
		
		//MenuPane jp = null;
		PluginOptionPanel panel = new PluginOptionPanel();
		/*try	{
			//..as to why we use this instead of simply toolkit.getimage... 
			jp = new MenuPane(javax.imageio.ImageIO.read(new File("resources/menupane.png")));
		}	catch(Exception x)	{
			x.printStackTrace();
		}
		jp.setLayout(null);
			*/	
		return panel;
	}
	
	
	/**
	 * Show a dialog with various tools and utilities for painting
	 */
	private void showToolDialog()	{
		
		if(toolDialog == null)	{
			toolDialog = new JDialog(this);
			toolDialog.setIconImage(loadImage("resources/ui/wrench_screwdriver.png"));
			toolDialog.setLayout(new GridLayout(toolButtons.size()/2, 2));
			
			int width = 20;
			int height = 20;
			
			for(int i = 0; i < toolButtons.size(); i++)	{
				toolButtons.get(i).setSize(width, height);
				toolDialog.add(toolButtons.get(i));
				
			}
			
			toolDialog.setSize(50, 150);
			toolDialog.setLocation((Integer)settings.get("toolDialogX"), (Integer)settings.get("toolDialogY"));
			//jd.setAlwaysOnTop(true);
			toolDialog.setVisible(true);
			toolDialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
			
			toolDialog.addWindowListener(this);
			
			//settings.put("showToolDialog", = true;
			
			
			
		}	else	{
			toolDialog.setVisible(!toolDialog.isVisible());
			//settings.showTools = !settings.showTools;
		}
	
		
	}
	
	
	private void addNewLayer(String owner)	{
		layers.add(createLayer((Integer)settings.get("canvasWidth"), (Integer)settings.get("canvasHeight"), owner));
		refreshLayerJList();
	}
	
	/**
	 * Display the Layers Dialog
	 */
	private void doLayersWindow()	{
		if(layerDialog != null)	{
			layerDialog.setVisible(!layerDialog.isVisible());
		}
		else	{
			
			layerDialog = new JDialog(this);
			layerDialog.setSize((Integer)settings.get("layerDialogWidth"), (Integer)settings.get("layerDialogHeight"));
			layerDialog.setLocation((Integer)settings.get("layerDialogX"), (Integer)settings.get("layerDialogY"));
			
			
			refreshLayerJList();
			//add some kind of list for viewing layers
			
			layerDialog.setVisible(true);
		}	
	}
	
	private void refreshLayerJList()	{
		
		if(layerDialog != null)	{
			if(layerList != null)
				layerDialog.getContentPane().removeAll();
			
			layerList = new JList(layers.toArray());
			layerList.setSelectedIndex(selectedLayer);
			//layerList.setCellRenderer(new LayerCellRenderer());
			layerList.setSize(layerDialog.getSize());
			
			JScrollPane js = new JScrollPane(layerList);
			
			layerDialog.getContentPane().add(js);
			
			layerDialog.getContentPane().invalidate();
			
			layerDialog.validate();
		}
	}
	
	
	
	/**
	 * Run a dialog to allow the user to connect to a painting session
	 */
	private void doConnectDialog()	{
		
		JComponent[] components = new JComponent[] {
				new JLabel("Host"), new JTextField(),
				new JLabel("Port"), new JTextField() 
		};
		((JTextField)components[1]).setText((String)settings.get("networkHost"));
		((JTextField)components[3]).setText(((Integer)settings.get("networkPort")).toString());
		PDialog pd = new PDialog(components);
		pd.setSize(200, 200);
		pd.setVisible(true);
		
		//make sure the user didn't just cancel the operation
		if(!pd.canceled)	{
			JTextField f = (JTextField) components[1];
			JTextField f2 = (JTextField) components[3];
			
			
			
			try	{
				
				connect(f.getText(), Integer.parseInt(f2.getText()));
			}	finally	{
				//t.interrupt();
				//this.setGlassPane(new JLabel());
			}
			
		}
	}
	
	/**
	 * Run a dialog to allow the user to host a painting session and set options such as port
	 * Todo: Add a password field and encryption for packets
	 */
	private void doHostDialog()	{
		JComponent[] components = new JComponent[] {
				new JLabel("Port"), new JTextField() 
		};
		PDialog pd = new PDialog(components);
		pd.setSize(200, 200);
		pd.setVisible(true);
		if(!pd.canceled)	{
			JTextField f = (JTextField)	components[1];
			host(Integer.parseInt(f.getText()));
			//System.out.println("not hanging @ host");
		}
		//dialogs.add(pd);
	}
	
	/**
	 * Host a painting session
	 * @param port - The port to start the server on
	 */
	private void host(int port)	{
		try	{
			ServerConfig config = new ServerConfig();
			config.width = (Integer)settings.get("canvasWidth");
			config.height = (Integer)settings.get("canvasHeight");
			config.layerCount = (Integer)settings.get("layerCount");
			config.port = port;
			
			//TODO: Make sure to make the network manager start a server and open a connection to it here.
			//System.out.println("Starting local server...");
			//networkManager.startServer(config);
			//System.out.println("Local server started");
			
		}	catch(Exception x)	{
			x.printStackTrace();
		}
		
		
	}
	
	//Connect to an already hosted painting session
	private void connect(String host, int port)	{
		try	{
			networkManager.connect(host, port, (String)settings.get("username"));
			networkConnected = true;
			
		}	catch (Exception x)	{
			x.printStackTrace();
		}
	}

	//Handles all paint events
	//pack - the paint data
	//local specifies whether the packet was generated locally or
	//remotely
	BasicStroke stroke = null;
	
	
	//a dialog for creating a new image
	private void showNewImageDialog()	{
		
		if(canvas != null)	{
			JOptionPane.showMessageDialog(this, "An image is already open, please close the current image before creating a new one.");
			return;
		}
		
		SpinnerModel model = new SpinnerNumberModel((int)(Integer)settings.get("canvasWidth"), 1, 10000, 1);
		JSpinner widthField = new JSpinner(model);
		widthField.setEditor(new JSpinner.NumberEditor(widthField));
		model = new SpinnerNumberModel((int)(Integer)settings.get("canvasHeight"), 1, 10000, 1);
		JSpinner heightField = new JSpinner(model);
		
		//JTextField Field = new JTextField();
		JComboBox colorFields = new JComboBox(new String[]{"RGB", "ARGB", "Grayscale"});
		JComponent[] components = new JComponent[]	{
			new JLabel("Width:"), widthField, 
			new JLabel("Height:"), heightField, 
			new JLabel("Colorspace:"), colorFields 
		};
		
		
		
		PDialog jd = new PDialog(components);
		jd.setSize(300, 200);
		jd.setLocation(((Dimension)settings.get("screenSize")).width /2 - jd.getWidth()/2, ((Dimension)settings.get("screenSize")).height /2 - jd.getHeight()/2);
		jd.setTitle("New Image");
		jd.setResizable(false);
		
		jd.setVisible(true);
		if(!jd.canceled)	{
			settings.put("canvasWidth", (Integer)widthField.getValue());
			settings.put("canvasHeight", (Integer)heightField.getValue());
			newImage();
		}
		
	}
	
	
	
	/**
	 * Set up the canvas and create a new image
	 */
	private void newImage()	{
		if(canvas == null)	{
			initLayers((Integer)settings.get("layerCount")); // initialize the layers
			canvas = initCanvas(); //initialize the canvas
			setLayer(0);
			
			getContentPane().getLayout().layoutContainer(getContentPane());
			getContentPane().validate();
			
			//topToolbar.onPluginSelected(paintPlugins.get((Integer)settings.get("selectedPlugin")));
			//topToolbar.getComponent(0).repaint();
			repaint();
			
			
		}	else	{
			JOptionPane.showMessageDialog(this, "An image is already open, please close the current image before creating a new one.");
		}
	}
	
	private Packet onPaintPluginEvent(Packet p, Layer l)	{
			for(int i = 0; i < paintPlugins.size(); i++){
				if(paintPlugins.get(i).getHashValue() == p.pluginHash)	{
					return paintPlugins.get(i).onEvent(p, l, scratchLayer);
				}
			}
			
		return null;
	}
	
	/*private void handleChat(ChatPacket p)	{
		chatTextArea.append(p.username + ": " + p.message);
		chatTextArea.setPreferredSize(new Dimension(chatTextArea.getPreferredSize().width, chatTextArea.getRows()*10));
		chatTextArea.getParent().doLayout();
	}*/
	
	
	
	private void peerConnected(QueryPacket p)	{
		Layer[] layers = new Layer[undoCount];
		//undoStack.add(p.userID, layers);
		System.out.println("Peer connected, adding peer " + p.ownerHash);
		
	}
	
	private void peerDisconnected(QueryPacket p)	{
		System.out.println("Peer disconnected, removed peer " + p.ownerHash);
	}
	
	
	LayerHistoryManager historyManager = new LayerHistoryManager();
	//Handle the processing and subsequent painting of user input on the canvas/tool bars
	private void doPaint(Packet pack, boolean local)	{
		Rectangle2D updateArea =  null;
		
		pack = onPaintPluginEvent(pack, layers.get(pack.layerIndex));
		updateArea = pack.bounds;
		hasSaved = false;
		
		if(pack.mouseAction == Packet.MOUSE_ACTION_RELEASED && pack.packetType != Packet.PACKET_TYPE_QUERY)
			historyManager.onDo(layers.get(selectedLayer));
				
		if(networkConnected)
			networkManager.writePacket(pack);
		
		if(pack.mouseAction == Packet.MOUSE_ACTION_RELEASED)	{
			pack.lastX = pack.x;
			pack.lastY = pack.y;
			
			//if(layerList != null)
				//layerList.repaint();
		}
		
		//TODO: insert painting code here! (canvas.paintLayers(layers, boundsrect) )
		//make sure to accomodate for the scratch layer and the updateCanvas boolean declared in this method. 
		canvas.paintLayers(layers, updateArea, !scratchLayer.isModified());
		
		if(scratchLayer.isModified())	{
			canvas.compositeLayer(scratchLayer, updateArea, true);
			scratchLayer.setModified(false);
		}
		
		
	}
		
		
	//set the currently selected layer
	private void setLayer(int i)	{
		//this is obsolete code, and it's stupid. Erase it!
		//****READ ME****
		//The reason we even touch graphics here is to set the properties of the current Graphics2D context for this particular layer
		//selectedLayer = i;
		//graphics = local_layers.get(i).createGraphics();
		
		//if(settings.antiAliasingOn)	{
			//graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		//}
		
	}

	public void undo(String user)	{
		Layer l = historyManager.requestNextUndoLayer(user);
		//layers.set(l.index, l);
		layers.clear();
		layers.add(l);
		redrawAllLayers();
		System.out.println("Undoing layer for user: " + l.getOwner() + ", at index " + l.index);
	}
	
	public void redrawAllLayers()	{
		canvas.paintLayers(layers, new Rectangle2D.Double(0, 0, (Integer)settings.get("canvasWidth"), (Integer)settings.get("canvasHeight")), true);
	}
	
	//TODO: Consider cleaning this code!!
	//Action performed, used by ActionListener
	public void actionPerformed(ActionEvent e)	{
		if(e.getActionCommand() == "Layers")
			doLayersWindow(); // display the layers dialog
		else if(e.getActionCommand() == "Swatches")	
			toggleSwatchChooserDialog(); // display the swatches dialog
		else if(e.getActionCommand() == "New")	
			showNewImageDialog();
		else if(e.getActionCommand() == "Close")	{
			close();
		}
		else if(e.getActionCommand() == "Undo")	{
			undo((String)settings.get("username"));
		}
		else if(e.getActionCommand() == "Save")	
			if(layers.size() > 0)
				saveImage(layers.get(selectedLayer));
			else
				 JOptionPane.showMessageDialog(null, "No image available to save.", "Error", JOptionPane.ERROR_MESSAGE);
		else if(e.getActionCommand() == "Connect..." || e.getActionCommand() == "Connect to...")
			doConnectDialog(); // connect to a remote host
		else if(e.getActionCommand() == "Host")
			doHostDialog(); // host a painting session
		else if(e.getActionCommand() == "Tools")
			showToolDialog();
		else if(e.getActionCommand() == "New Layer")	{
			addNewLayer((String)settings.get("username"));
		}
		else if(e.getActionCommand() == "Network Options")
			dialogNetworkOptions();
		else if(e.getActionCommand() == "Chat")
			;//TODO: add code here to show a chat dialog!!
		else if(e.getActionCommand().startsWith("TOOL_PLUGIN"))	{
			int id = Integer.parseInt(e.getActionCommand().split(" ")[1]); //parses the ID out of the action command
			selectedPlugin = id;
			//setToolbar(paintPlugins.get(id).getToolbar(new Dimension(getWidth(), 50)));
			topToolbar.onPluginSelected(paintPlugins.get(id));
			topToolbar.getComponent(0).repaint();
			tool = TOOL_PLUGIN;
			
		}
		
		else if(e.getActionCommand() == SwatchPanel.defaultActionCommand)	{
			settings.put("primaryColor", ((SwatchPanel)e.getSource()).getSelectedColorPrimary());
		}
			
		
		
		else if(e.getActionCommand() == "Exit")
			exit(0);
			
			
	}	

	private void close()	{
		if(hasSaved)	{
			
		}
		else	{
			
			JOptionPane pane = new JOptionPane((Object)"You have not saved your work, would you like to do so now?", JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.INFORMATION_MESSAGE);
			JDialog d = pane.createDialog("Warning!");
			d.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
			d.setVisible(true);
			Object selectedValue = pane.getValue();
			if(selectedValue == null)	{	
				hasSaved = false;
				return;
			}
			else if(((Integer)selectedValue).intValue() == JOptionPane.YES_OPTION)	{
				saveImage(layers.get(selectedLayer));
				//if(hasSaved)
					//return;
			}
			else if(((Integer)selectedValue).intValue() == JOptionPane.NO_OPTION)	{
				hasSaved = true;
				//return;
			}
			
			if(hasSaved)	{
				getContentPane().remove(canvas.getParent().getParent());
				layers.clear();
				canvas = null;
				
				getContentPane().getLayout().layoutContainer(getContentPane());
				repaint();
				
			}
						
		}
	}
	
	
	private void exit(int i)	{
		close();
		if(hasSaved)	{
			saveSettings();
			unloadPlugins();
			dispose();
			System.exit(i);
		}
			
		
	}
	
	public void windowActivated(WindowEvent e)	{
		/*
		boolean localFocus = false;
		for(int i = 0; i < dialogs.size(); i++)
			if(dialogs.get(i).hasFocus())
				localFocus = true;
		if(!localFocus)
			for(int i = 0; i < dialogs.size(); i++)	{
				JDialog d = dialogs.get(i);
				if(d != null)
					d.setAlwaysOnTop(true);
			}
			*/
	}
	
	public void windowClosed(WindowEvent e)	{
		
		
	}
	public void windowClosing(WindowEvent e) {
		if(e.getSource() instanceof JDialog)
			((JDialog)e.getSource()).setVisible(false);
		if(e.getSource() instanceof JFrame)	
			exit(0);
	}
	
	public void windowDeactivated(WindowEvent e)	{
		/*boolean localFocus = false;
		for(int i = 0; i < dialogs.size(); i++)
			if(dialogs.get(i).hasFocus())
				localFocus = true;
		
		if(!localFocus)	{
			for(int i = 0; i < dialogs.size(); i++)	{
				JDialog d = dialogs.get(i);
				
					if(d != null)
						d.setAlwaysOnTop(false);
			}
		}
		*/
		
	}
	public void windowDeiconified(WindowEvent e)	{
		
	}
	
	public void windowIconified(WindowEvent e)	{
		/*Frame[] frames = getFrames();
		for(int i = 0; i < frames.length; i++)	{
			//Window[] windows = getOwnerlessWindows();
			//windows[i].setVisible(false);
			if(!frames[i].equals(this))
				frames[i].setState(Frame.ICONIFIED);
			System.out.println(i);
			*/
		//}
	}
	public void windowOpened(WindowEvent e)	{
		/*Frame[] frames = getFrames();
		for(int i = 1; i < frames.length; i++)	{
			if(!frames[i].equals(this))
				frames[i].setState(Frame.NORMAL);
		}
		*/
	}
	
	
	
	/**
	 * indicates whether the program is running in debug mode or in release-mode
	 */
	public static final boolean DEBUG_VERSION = true;
	
	/**
	 *Call this method if, when not in debug mode, the message should be written to a log file, otherwise it is written to the terminal
	 *@param s - string to write
	 */
	public static void logMsg(String s)	{
		System.out.println(s);
		
	}
	
	/**
	 * use this method when a message should only be written to the console, while in debug mode
	 * @param s - String to write
	 */
	public static void debugMsg(String s)	{
		if(DEBUG_VERSION)
			System.out.println(s);
	}
	
	//Main... 
	public static void main(String[] args)	{
		
		if(!DEBUG_VERSION)	{
			try	{
				FileOutputStream fos = new FileOutputStream("/dymndlog.txt");
				System.setErr(new PrintStream(fos));
				System.setOut(new PrintStream(fos));
			}	catch(Exception x)	{
				x.printStackTrace();
			}
		}
		Client c = new Client(args);
	}

}
